home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 101-125 / disk_108 / alist / alist.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  24KB  |  786 lines

  1. /* "AList" 0.06 ... Disk Directory (catalog) Utility by Ed Kivi */
  2.   
  3. /* This command is designed to get an AmigaDOS directory and display the
  4.    full contents to the screen.  Later it will create an AmigaDOS file
  5.    of PathNames to be used as a Library of files on disk storage.    */
  6.   
  7. #include <exec/types.h>   /* order is important, else "NULL" */
  8. #include <stdio.h>
  9. #include <ctype.h>        /* will be 'redefined' in compiler's eye */
  10. #include <time.h>
  11. #include <libraries/dosextens.h>
  12. #include <exec/memory.h>
  13.  
  14. /* #define AEKfilenote       -* long version of aekDC desired */
  15. #undef  AEKfilenote       /* short version of aekDC desired */
  16. #undef  DEBUG             /* [dis|en]able de-bugging printf statements */
  17.  
  18. #ifndef  HIGHVALUE
  19. #define  HIGHVALUE     127
  20. #endif
  21.  
  22. #define  AmigaFIB      struct FileInfoBlock
  23. #define  aekDC         struct DCatalog      /* A. E. Kivi Disk Catalog */
  24. #define  volsize       31     /* maximum length of volume name (31) */
  25. #ifndef  AEKfilenote
  26. #define  pathsize      36     /* maximum length of path name */
  27. #else
  28. #define  pathsize      61     /* maximum length of path name */
  29. #endif
  30. #define  filesize      31     /* maximum length of file name (31) */
  31. #define  extsize       11     /* maximum length of file name extension */
  32.   
  33. extern struct FileLock *Lock();
  34.  
  35. /* preliminary disk catalog record layout, growing from Ram: to file */
  36.    aekDC
  37.    {
  38.    aekDC    *DC_next;            /* pointer to next record */
  39.    aekDC    *DC_prior;           /* pointer to prior record */
  40. #ifdef   AEKfilenote
  41.    aekDC    *DC_altnext;         /* pointer to next record (alt seq) */
  42.    aekDC    *DC_altprior;        /* pointer to prior record (alt seq) */
  43. #endif
  44.    long      DC_key;             /* Ram: address, Disk: track */
  45.    long      DC_size;            /* 0, or size in bytes of a file */
  46.    long      DC_blocks;          /* number of blocks required */
  47.    char      DC_type;            /* V= Volume, D= Directory, F= File */
  48.    char      DC_volume[volsize]; /* disk name, as "WorkBench_1.2" */
  49.    char      DC_path[pathsize];  /* first 'n' chars of the Path Name */
  50.    char      DC_file[filesize];  /* file name, as "DLibrary" */
  51.    char      DC_ext[extsize];    /* extension, as ".c" (without .) */
  52.    char      DC_icon;            /* Y = has .info, N = no .info */
  53.    char      DC_dmy[12];         /* Date, as "05-Sep-1987 " */
  54.    char      DC_time[9];         /* Time-of-day, as "14:45:13" */
  55. #ifdef   AEKfilenote
  56.    char      DC_filenote[71];    /* Comments about the file */
  57. #endif
  58.    } ;
  59.  
  60. /* This is probably unnecessary, but nothing obvious in AmigaDOS */
  61.    struct Calendar
  62.    {
  63.    int  yearday;          /* number of days in prior months, as "243" */
  64.    int  lastday;          /* last day in the month, as "30" */
  65.    char monname[4];       /* month name, as "Sep " */
  66.    } ;
  67.  
  68. /* This is the format used by gmtime() and localtime() */
  69.    struct DateTime
  70.    {
  71.    char DT_wday[4];       /* Day-of-the-week, as "Sat" */
  72.    char DT_month[4];      /* month name, as "Sep " */
  73.    char DT_mday[3];       /* Day-of-the-month, as "05" */
  74.    char DT_time[9];       /* Time-of-day, as "14:45:13" */
  75.    char DT_year[5];       /* Year, as "1987" */
  76.    char DT_filler[1];     /* NewLine */
  77.    } ;
  78. /* replace/rename above when (if?) found in AmigaDOS */
  79.  
  80.    AmigaFIB         *fb;         /* File Info from locked directory */
  81.    struct FileLock  *dir;        /* Locked AmigaDOS directory */
  82.    struct FileLock  *olddir;     /* AmigaDOS directory to be restored */
  83.    struct DateTime  *ud;         /* Date stamp info from FileInfoBlock */
  84.    aekDC            *pdc;        /* Disk Catalog record to be inserted */
  85.    aekDC            *pdc1;       /* Root (Volume) Disk Catalog record */
  86.    aekDC            *pdEnd;      /* End-of-List Disk Catalog record */
  87.    aekDC            *pdTop;      /* Directory record #1 (Volume Name only) */
  88.    int               nestedDir;  /* number of sub-directories found */
  89.    aekDC            *pdirn;      /* last Directory record (Path only) */
  90.    aekDC            *pdir;       /* Directory record (Path Name only) */
  91.    aekDC            *getDCmem(aekDC *); /* storage for Disk Catalog record */
  92.  
  93.    char   *append( char *, char *, int );  /* string concatenation */
  94.    char   *copyn( char *, char *, int );   /* Copy n chars. */
  95.    char   *copy( char *, char * );         /* Copy string of chars. */
  96.    char   *fill_area( char *, unsigned char, int ); /* string (area) fill */
  97.    char   *ign;                /* throw-away pointer from memset */
  98.    char    DiskName[volsize];  /* name of the disk from FileInfoBlock */
  99.    char    dirname[volsize];   /* name of the disk: from FileInfoBlock */
  100.    char    work[108];          /* volume/path/file name work area */    
  101.  
  102.    int     compareci( char *, char * );    /* string compare, case insensitive */
  103.    static int        keyed    = 0;  /* return from 'getchar' */
  104.    static int        calls    = 0;  /* number of entries in core */
  105.    static int        passno   = 0;  /* number of directory passes made */
  106.    static int        fullpage = 22; /* number of lines displayed per page */
  107.    static int        thispage = 0;  /* number of lines displayed so far */
  108.    static int        bytes    = 0;  /* number of bytes stored on disk */
  109.    static int        blocks   = 0;  /* number of blocks on disk used */
  110.    static int        mask     = 0;  /* clean-up requirement indicators */
  111. #define   allocud    0x00000001     /* allocated storage for DateTime */
  112. #define   allocfb    0x00000002     /* allocated storage for FileInfoBlock */
  113. #define   svolddir   0x00000004     /* saved old directory */
  114. #define   allocpdTop 0x00000010     /* allocated storage for Head-of-List */
  115. #define   allocpdEnd 0x00000020     /* allocated storage for Tail-of-List */
  116. #define   allocpdc   0x00000040     /* allocated storage for at least 1 record */
  117.  
  118.    BOOL              fail;          /* Directory Access Failure */
  119.    BOOL              noargs   = FALSE;   /* TRUE if argument(s) supplied */
  120.    BOOL              color    = FALSE;   /* TRUE if color display desired */
  121.    BOOL              verbose  = FALSE;   /* TRUE if Version, count, etc. */
  122.    BOOL              redirect = FALSE;   /* TRUE if >prt: being used */
  123.  
  124.    void              close_things(); /* clean-up memory, etc. */
  125.    void              Delay();        /* delay for de-bugging */
  126.    void              usage();        /* invalid argument(s), display usage */
  127.    void              options( char *, int );  /* parse options */
  128.    void              Traverse( aekDC *, int, struct FileLock * );
  129.    void              MergeDC( aekDC * , aekDC * , aekDC * ); /* Filer */
  130.    void              print_headings();     /* headings over column data */
  131.  
  132. void
  133. main(argc,argv)
  134.  
  135. int argc;
  136. char *argv[];
  137.  
  138. {
  139.  
  140.    int    ai = 0;
  141.  
  142.    if ( argc >= 7 )
  143.         usage();
  144.    if (argc == 1)
  145.      {
  146.       ign = copy( dirname, "" );
  147.       noargs = TRUE;
  148.      }
  149.    else
  150.         {
  151.          while ( argv [ai + 1] && ai++ <= argc - 1 )
  152.                {
  153.                  ign = copy( work, argv [ai] );
  154.                  if ( work[0] == '?' )
  155.                       usage();
  156.                  if ( ( work[0] == 'o' || work[0] == 'O') && (work[1] == 'p' || work[1] == 'P') && ( work[2] == 't' || work[2] == 'T') )
  157.                      {
  158.                       ign = copy( work, argv [++ai] );
  159.                       options( work, 0);
  160.                      }
  161.                  else
  162.                       {
  163.                        if ( work[0] == '-' )
  164.                             options( work, 1);
  165.                        else
  166.                            {
  167.                             ign = copy( dirname, work );
  168.                             if ( dirname == '\0' )
  169.                                  usage();
  170.                            }
  171.                       }    
  172.                }
  173.         }
  174.  
  175.    if ( fullpage < 3 )
  176.         fullpage = 22;
  177.  
  178.    ud  = (struct DateTime *) AllocMem( sizeof( struct DateTime ), MEMF_CLEAR | MEMF_PUBLIC );
  179.    mask |= allocud;
  180.    fb  = (AmigaFIB *) AllocMem( sizeof( AmigaFIB ), MEMF_CLEAR | MEMF_PUBLIC );
  181.    mask |= allocfb;
  182.    dir = Lock(dirname, ACCESS_READ);
  183.    if ( !dir )
  184.       {
  185.        printf( "Could not Lock '%s'.\n", dirname );
  186.        close_things();
  187.       }
  188.    olddir = CurrentDir( dir );
  189.    mask |= svolddir;
  190.  
  191. /*       Read "Root" directory FileInfoBlock */
  192.  
  193.    fail = (dir == NULL) | !Examine(dir,fb);
  194.    if (fail) {
  195.       printf("Sorry, '%s' is not a directory\n", dirname);
  196.       close_things();
  197.    }
  198.    ign =   copy( work, fb->fib_FileName );
  199.    ign = append( work, ":", sizeof(work) );
  200.    if ( work[0] == ':' )
  201.        ign = copy( work, dirname );
  202.    work[volsize-1] = '\0';
  203.    ign = copy( DiskName, work );
  204.  
  205. /*       Build specified Root directory name and information */
  206.  
  207.    pdTop            = getDCmem( NULL );  /* get memory for top-of-list */
  208.    if ( !pdTop )
  209.         close_things();
  210.    mask |= allocpdTop;
  211.    pdTop->DC_key    = fb->fib_DiskKey;
  212.    pdTop->DC_size   = 0;
  213.    pdTop->DC_blocks = fb->fib_NumBlocks;
  214.    pdTop->DC_type   = 'V' ;
  215.    ign = copy( pdc->DC_volume, DiskName );
  216.    ign = fill_area( pdTop->DC_path, (unsigned char) '\0', sizeof(pdTop->DC_path) );
  217.    ign = fill_area( pdTop->DC_file, (unsigned char) '\0', sizeof(pdTop->DC_file) );
  218.    ign = fill_area( pdTop->DC_ext,  (unsigned char) '\0', sizeof(pdTop->DC_ext) );
  219.    pdTop->DC_icon = 'N' ;
  220.  
  221. /* Root entry has been initialized */
  222.  
  223.    pdEnd           = getDCmem( pdTop );  /* get memory for end-of-list */
  224.    if ( !pdEnd )
  225.         close_things();
  226.    mask |= allocpdTop;
  227.    pdTop->DC_prior = NULL;
  228.    pdEnd->DC_next  = NULL;
  229.    pdTop->DC_next  = pdEnd;
  230.    pdEnd->DC_prior = pdTop;
  231.    ign = fill_area( pdEnd->DC_volume, (unsigned char) HIGHVALUE, sizeof(pdEnd->DC_volume) );
  232.    ign = fill_area( pdEnd->DC_path,   (unsigned char) HIGHVALUE, sizeof(pdEnd->DC_path) );
  233.    ign = fill_area( pdEnd->DC_file,   (unsigned char) HIGHVALUE, sizeof(pdEnd->DC_file) );
  234.    ign = fill_area( pdEnd->DC_ext,    (unsigned char) HIGHVALUE, sizeof(pdEnd->DC_ext) );
  235.  
  236. /* End-of-list entry has been initialized */
  237.  
  238.    pdc1  = pdTop;           /* This one gets changed */
  239.    pdc   = pdc1;            /* set generic pointer to root */
  240.    calls--;                 /* do not count end-of-list */
  241.  
  242. /*      Build File and Directory records, Print from record */
  243.  
  244.    if ( redirect )          /* form feed and indent for printer */
  245.         printf( "\f      " );
  246.    if ( verbose )
  247.       {
  248.         printf( "\033[1mAList V0.06\033[0m compiled at 14:45:13 on Sat 05-Sep-1987.\n" );
  249.         thispage = 2;
  250.       }
  251.    Traverse( pdc1, passno, dir );
  252.  
  253.    print_headings();
  254.    pdc = pdTop;
  255.  
  256. /*       Print specified directory name and information */
  257.  
  258.    while ( pdc != pdEnd)
  259.      {
  260.       if ( !redirect && verbose && thispage >= fullpage )
  261.          {
  262.            printf( "Press \033[37m\033[3menter\033[0m to continue." );
  263.            keyed = getchar();
  264.            thispage = 0;
  265.            print_headings();
  266.          }
  267.       if ( redirect )
  268.            printf( "      " );         /* indent for printer */
  269.       if ( pdc->DC_type == 'V' )
  270.          printf( "\033[1m%-30s ", pdc->DC_volume );
  271.       else
  272.           {
  273.            if ( pdc->DC_type == 'D' )
  274.               {
  275.                 if ( color )
  276.                      printf( "\033[37m" );
  277.                 printf( "\033[3m%-30s ", pdc->DC_path );
  278.               }
  279.            else
  280.                {
  281.                 if ( pdc->DC_path[0] == '\0' )
  282.                     ign = copy( work, pdc->DC_file );
  283.                 else
  284.                     {
  285.                       ign = copy( work, "  " );
  286.                       ign = append( work, pdc->DC_file, sizeof(work) );
  287.                     }
  288.                 work[volsize-1] = '\0';
  289.                 printf( "%-30s ", work);
  290.                }
  291.           }
  292.       printf( "%7d ", pdc->DC_key );
  293.       if ( pdc->DC_type == 'V' )
  294.            printf( "  Root ");
  295.       else if ( pdc->DC_type == 'D' )
  296.                 printf( "   Dir " );
  297.            else
  298.               {
  299.                bytes += pdc->DC_size;
  300.                printf( "%6d ", pdc->DC_size );
  301.               }
  302.       blocks += pdc->DC_blocks;
  303.       printf( "%4d ", pdc->DC_blocks );
  304.       printf( "%s ", pdc->DC_dmy );
  305.       printf( "%s\033[0m\n", pdc->DC_time );
  306.       thispage++;
  307.       pdc1 = pdc;
  308.       pdc = pdc->DC_next;
  309.       pdTop->DC_next = pdc;    /* remove record from the linked-list */
  310.       if ( pdc1 != pdTop )
  311.            FreeMem( pdc1, sizeof(aekDC) ); /* Free memory for 2 -> n-1 */
  312.      }
  313.    mask ^= allocpdc;           /* freed all file/directory records */
  314.    if ( redirect )
  315.         printf( "      " );         /* indent for printer */
  316.    printf( "%d members in %d blocks, storing %d bytes.\n", calls, blocks, bytes );
  317.    close_things();
  318. }                     /* end of main-line of program "DLibrary" */
  319.  
  320. /*       Append a string to the end of a string up to 'limit' characters. */
  321.  
  322. char *append( to, from, limit )
  323.  
  324. char    *to;
  325. char    *from;
  326. int      limit;
  327.  
  328. {
  329.     char    *temp = to;
  330.  
  331.     if ( !to )
  332.         return( temp );
  333.  
  334.     while ( *to && limit > 1 )   /* find current end-of-string */
  335.           {
  336.            to++;
  337.            limit--;
  338.           }
  339.  
  340.     while ( *from && limit > 1 ) /* extend string */
  341.           {
  342.            *to = *from++;
  343.            to++;
  344.            limit--;
  345.           }
  346.  
  347.     *to++ = '\0';                /* ensure NULL terminated */
  348.     return( temp );
  349. }
  350.  
  351. /*        Close off (as friendly as possible) */
  352.  
  353. void close_things()
  354.  
  355. {
  356.   if ( mask & allocud )                 /* FreeMem for date work area */
  357.        FreeMem( ud, sizeof(struct DateTime) );
  358.   if ( mask & allocfb )                 /* FreeMem for FileInfoBlock */
  359.        FreeMem( fb, sizeof(AmigaFIB) );
  360.   if ( mask & allocpdTop )              /* at least 1 record allocated */
  361.      {
  362.        if ( mask & allocpdc )           /* FreeMem for 2 -> n-1 */
  363.           {
  364.             pdc = pdTop->DC_next;
  365.             while ( pdc != pdEnd)
  366.               {
  367.                pdc1 = pdc;
  368.                pdc = pdc->DC_next;
  369.                pdTop->DC_next = pdc;    /* maintain the linked-list */
  370.                if ( pdc1 != pdTop )
  371.                     FreeMem( pdc1, sizeof(aekDC) );
  372.               }
  373.           }
  374.        FreeMem( pdTop, sizeof(aekDC) ); /* FreeMem for record 1 */
  375.      }
  376.   if ( mask & allocpdEnd )
  377.        FreeMem( pdEnd, sizeof(aekDC) ); /* FreeMem for record n */
  378.   if ( mask & svolddir )
  379.        dir = CurrentDir( olddir );
  380.   Exit();
  381. }
  382.  
  383. /*        Compares string to string (case insensitive). */
  384.  
  385. int  compareci( to, from )
  386.  
  387. char    *to;
  388. char    *from;
  389.  
  390. {
  391.     char    a;
  392.     char    b;
  393.     int     c;
  394.  
  395.     for ( ; ; *to++, *from++ )
  396.         {
  397.           a = *to;
  398.           b = *from;
  399.           if ( a >= 'A' && a <= 'Z' )
  400.                a = a - 'A' + 'a';
  401.           if ( b >= 'A' && b <= 'Z' )
  402.                b = b - 'A' + 'a';
  403.           c = ( int ) a - ( int) b;
  404.           if ( c || !a || !b )
  405.               return( c );
  406.         }
  407. }
  408.  
  409. /*     Copy string of characters (ending with NULL terminator) */
  410.  
  411. char    *copy( to, from )
  412.  
  413. char    *to;      /* destination string */
  414. char    *from;    /* source string */
  415.  
  416. {
  417.     char    *temp = to;
  418.  
  419.     while ( to && *from )         /* no zero destination allowed */
  420.            *to++ = *from++;
  421.     *to++ = '\0';
  422.  
  423.     return(temp);
  424. }
  425.  
  426. /*     Copy exactly "n" characters (regardless of NULL terminator) */
  427.  
  428. char    *copyn(to, from, n)
  429.  
  430. char    *to;      /* destination string */
  431. char    *from;    /* source string */
  432. int     n;        /* number of characters to be copied */
  433.  
  434. {
  435.     char    *temp = to;
  436.  
  437.     while ( n-- && to )           /* no zero destination allowed */
  438.            ( *to++ = *from++ );
  439.  
  440.     return(temp);
  441. }
  442.  
  443. /*       Fills a string with the specified character. */
  444.  
  445. char *fill_area( to, what, howmany)
  446.  
  447.          char    *to;
  448. unsigned char     what;
  449.          int      howmany;
  450.  
  451. {
  452.     char    *temp = to;
  453.  
  454.     while ( howmany-- > 1 )
  455.        {
  456.         *to++ = what;
  457.        }
  458.  
  459.     *to = '\0';
  460.  
  461.     return(temp);
  462. }
  463.  
  464. /*     get memory to use as Disk Catalog record */
  465.  
  466. aekDC *getDCmem(source)
  467.  
  468. aekDC *source;
  469.  
  470. {
  471.  
  472.    pdc = (aekDC *) AllocMem( sizeof( aekDC ), MEMF_CLEAR | MEMF_PUBLIC );
  473.  
  474.    if ( !pdc )
  475.       {
  476.        printf( "Out of memory large enough for another record.\n" );
  477.        return( pdc );
  478.       }
  479.    calls++;
  480.    if ( source )
  481.        ign = copyn( (char *) pdc, (char *) source, sizeof(aekDC) );
  482.    UnDateStamp(ud, fb);
  483.    return(pdc);
  484.  
  485. }
  486.  
  487. /*     Find proper location for "New", given ("Top", "End", "New"). */
  488.  
  489. void   MergeDC(top, end, new)
  490.  
  491. aekDC *top;
  492. aekDC *end;
  493. aekDC *new;
  494.  
  495. {
  496.  
  497.   int    HiLo;
  498.  
  499.   while (top != end)   /* someone created a highvalues disk/path/file */
  500.      {
  501.       HiLo = compareci( top->DC_volume, new->DC_volume );
  502.       if (HiLo > 0)
  503.           break;
  504.         if (!HiLo)
  505.          {
  506.           HiLo = compareci( top->DC_path, new->DC_path );
  507.           if (HiLo > 0)
  508.               break;
  509.             if (!HiLo)
  510.              {
  511.               HiLo = compareci( top->DC_file, new->DC_file );
  512.               if (HiLo > 0)
  513.                   break;
  514.                 if (!HiLo)
  515.                  {
  516.                   HiLo = compareci( top->DC_ext, new->DC_ext );
  517.                   if (HiLo > 0)
  518.                       break;
  519.                  }
  520.              }
  521.          }
  522.       top = top->DC_next;
  523.      }
  524.  
  525.       top           = top->DC_prior;
  526.  
  527.       end           = top->DC_next;
  528.       new->DC_next  = top->DC_next;
  529.       new->DC_prior = top;
  530.       top->DC_next  = new;
  531.       end->DC_prior = new;
  532. }
  533.  
  534. /*       Parse option string(s) and set indicators */
  535.  
  536. void options( array, oi )
  537.  
  538. char   array[];
  539. int    oi;
  540.  
  541. {
  542.  
  543.   int   i = 0, j = 0;
  544.  
  545.   while ( array[ oi + i ] )
  546.   {
  547.   if ( array[ oi + i ] == 'c' || array[ oi + i ] == 'C' )
  548.      {
  549.        color = TRUE;
  550.        i++;
  551.      }
  552.   else if ( array[ oi + i ] == 'v' || array[ oi + i ] == 'V' )
  553.           {
  554.             verbose = TRUE;
  555.             i++;
  556.           }
  557.   else if ( array[ oi + i ] == 'p' || array[ oi + i ] == 'P' )
  558.           {
  559.             redirect = TRUE;
  560.             i++;
  561.           }
  562.        else
  563.           {
  564.           if ( array[ oi + i ] == 'l' || array[ oi + i ] == 'L' )
  565.               {
  566.                fullpage = 0;
  567.                for ( j = 0; j = 2; j++ )
  568.                   {
  569.                     i++;
  570.                     if ( array[ oi + i ] >= '0' && array[ oi + i ] <= '9' )
  571.                        {
  572.                          fullpage *= 10;
  573.                          fullpage += array[ oi + i ] - '0';
  574.                        }
  575.                     else
  576.                          break;
  577.                   }
  578.              }
  579.           else
  580.                usage();
  581.           }
  582.   }
  583. }
  584.  
  585. /*       Print "Headings" for information display */
  586.  
  587. void print_headings()
  588.  
  589. {
  590.    printf( "\n" );
  591.    if ( redirect )
  592.         printf( "      " );         /* indent for printer */
  593.    printf("F_i_l_e___N_a_m_e_____________ ");
  594.    printf("__Keys_ ");
  595.    printf("_Size_ ");
  596.    printf("Blks ");
  597.    printf("DD-MMM-YYYY ");
  598.    printf("__Time__\n");
  599.    thispage++;
  600.  
  601. }
  602.  
  603. /* Traverse a Directory until ERROR_NO_MORE_ENTRIES
  604.  
  605. *    parent points to the directory record in core
  606. *    level is the number of ancestors in core        */
  607.  
  608. void Traverse( parent, Level, pasdir )
  609.  
  610. aekDC            *parent; /* Parent record to be cloned */
  611. int               Level;  /* Number of branches from the trunk */
  612. struct FileLock  *pasdir; /* AmigaDOS directory I am examining */
  613.  
  614. {
  615.  
  616.    struct FileLock  *mydir;  /* AmigaDOS directory my child will examine */
  617.  
  618.    char    mydirname[volsize+pathsize];  /* Selected AmigaDOS directory */
  619.  
  620.    int     subs = 0;         /* number of sub-directories I found */
  621.  
  622.    Level++;
  623.    while ( ExNext( dir, fb) != 0 || IoErr() != ERROR_NO_MORE_ENTRIES )
  624.    {
  625.       pdc = getDCmem( parent );
  626.       if ( pdc )
  627.            mask |= allocpdc;
  628.       else
  629.            break;
  630.       if ( verbose && !redirect )
  631.            printf( "%02d Files/Directories in Level %02d.\r", calls, Level);
  632.  
  633.       pdc->DC_key = fb->fib_DiskKey;
  634.       pdc->DC_size = 0;
  635.       pdc->DC_blocks = fb->fib_NumBlocks;
  636.       if ( fb->fib_DirEntryType > 0 )
  637.         {
  638.          subs++;
  639.          pdc->DC_type = 'D' ;
  640.          pdc->DC_size = ( long ) Level;
  641.          if ( pdc->DC_path[0] == ' ' || !pdc->DC_path[0] )
  642.              {
  643.               ign = copy( pdc->DC_path, "" );
  644.              }
  645.          else
  646.              {
  647.               ign = append( pdc->DC_path, "/", sizeof(pdc->DC_path) );
  648.              }
  649.          ign = append( pdc->DC_path, fb->fib_FileName, sizeof(pdc->DC_path) );
  650.         }
  651.       else
  652.         {
  653.          pdc->DC_size = fb->fib_Size;
  654.          pdc->DC_type = 'F' ;
  655.          ign = copy( pdc->DC_file, fb->fib_FileName );
  656.         }
  657.       MergeDC( parent, pdEnd, pdc );
  658.    }
  659.    UnLock( pasdir );            /* release parent directory */
  660.    while ( subs-- > 0 )
  661.      {
  662.       pdc = parent;
  663.       while ( pdc->DC_type != 'D' || pdc->DC_size == 0 )
  664.              { if ( pdc->DC_volume[0] == HIGHVALUE )
  665.                     break;
  666.                else
  667.                     pdc = pdc->DC_next;
  668.              }
  669.       pdc->DC_size = 0;
  670.       ign = copy( mydirname, pdc->DC_volume );
  671.       ign       = append( mydirname, pdc->DC_path, sizeof(mydirname) );
  672.       mydir     = Lock( mydirname, ACCESS_READ );
  673.       if ( !mydir | !Examine( mydir, fb ) )
  674.          {
  675.           printf( "Program error, '%s' is not a directory\n", mydirname );
  676.           close_things();
  677.          }
  678.       Traverse( pdc, Level, mydir ); /* follow limb thru branches to leaves */
  679.      }
  680. }
  681.  
  682. /*     Translate DateStamp to "Sat Sep 05 14:45:13 1987 !" */
  683.  
  684. UnDateStamp( o, i )
  685.  
  686. struct DateTime  *o;
  687. AmigaFIB         *i;
  688.  
  689. {
  690.  
  691.    static struct Calendar Mon_table[] =
  692.     {
  693.           0,  0, "   ",   /* null entry for month number "00" */
  694.           0, 31, "Jan",   /* non-leap year calendar */
  695.          31, 28, "Feb",
  696.          59, 31, "Mar",
  697.          90, 30, "Apr",
  698.         120, 31, "May",
  699.         151, 30, "Jun",
  700.         181, 31, "Jul",
  701.         212, 31, "Aug",
  702.         243, 30, "Sep",
  703.         273, 31, "Oct",
  704.         304, 30, "Nov",
  705.         334, 31, "Dec",
  706.           0, 31, "Jan",   /* leap year calendar */
  707.          31, 29, "Feb",
  708.          60, 31, "Mar",
  709.          91, 30, "Apr",
  710.         121, 31, "May",
  711.         152, 30, "Jun",
  712.         182, 31, "Jul",
  713.         213, 31, "Aug",
  714.         244, 30, "Sep",
  715.         274, 31, "Oct",
  716.         305, 30, "Nov",
  717.         335, 31, "Dec"
  718.     } ;
  719.  
  720. /*             Day-of-the-week array        */
  721.    static char WeekDays[][4] =
  722.        {
  723.         "Sun",
  724.         "Mon",
  725.         "Tue",
  726.         "Wed",
  727.         "Thu",
  728.         "Fri",
  729.         "Sat"
  730.        } ;
  731.  
  732.    int h, m, s, d, mm, y, ly, wd, j;       /* work fields */
  733.  
  734.    d = i->fib_Date.ds_Days - 1;            /* days since 12/31/1977 */
  735.   wd = i->fib_Date.ds_Days % 7;            /* day-of-the-week */
  736.    y = 1978;                               /* years (base was 1978) */
  737.    for (;;)
  738.       {
  739.        h = y % 4;
  740.        if (h = 0)
  741.             ly = 12;
  742.        else
  743.             ly = 0;
  744.        j = Mon_table[12+ly].yearday + Mon_table[12+ly].lastday;
  745.        if (d >= j)
  746.           {
  747.            y++;
  748.            d = d - j;
  749.           }
  750.        else
  751.            break;
  752.       }
  753.    for (mm = 1; mm < 13; mm++)
  754.        if (d > Mon_table[mm+ly].lastday)
  755.               d = d - Mon_table[mm+ly].lastday;
  756.        else break;
  757.    h = i->fib_Date.ds_Minute / 60;              /* hours */
  758.    m = i->fib_Date.ds_Minute % 60;              /* minutes */
  759.    s = i->fib_Date.ds_Tick / TICKS_PER_SECOND;  /* seconds */
  760.    ign = copy(o->DT_wday, WeekDays[wd]);
  761.    ign = copy(o->DT_month, Mon_table[mm].monname);
  762.    sprintf(o->DT_mday, "%02d", d);
  763.    sprintf(o->DT_time, "%02d:%02d:%02d", h, m, s);
  764.    sprintf(o->DT_year, "%04d", y);
  765.    ign = copy(   pdc->DC_dmy, o->DT_mday );
  766.    ign = append( pdc->DC_dmy, "-", sizeof(pdc->DC_dmy) );
  767.    ign = append( pdc->DC_dmy, o->DT_month, sizeof(pdc->DC_dmy) );
  768.    ign = append( pdc->DC_dmy, "-", sizeof(pdc->DC_dmy) );
  769.    ign = append( pdc->DC_dmy, o->DT_year, sizeof(pdc->DC_dmy) );
  770.    ign = copy( pdc->DC_time, o->DT_time );
  771.    return(0); 
  772.  
  773. }
  774.  
  775. /*       Display format of AList command */
  776.  
  777. void usage()
  778. {
  779.    printf("Usage: AList [>prt:] [dirname] [opt pcvl19 | -c -v -l45 -p]\n");
  780.    printf( " where: c=color display\n" );
  781.    printf( "        p=printer re-direction [>prt:] used\n" );
  782.    printf( "        v=verbose\n" );
  783.    printf( "    and l=lines/'page' (22 = full med-res CLI)\n");
  784.    Exit();
  785. }
  786.